package Engine.Model
{
	import Engine.Model.LogPrint;
	
	import Interface.Model.IResManager;
	
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.Loader;
	import flash.display.LoaderInfo;
	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.events.NetStatusEvent;
	import flash.events.ProgressEvent;
	import flash.events.SecurityErrorEvent;
	import flash.net.SharedObject;
	import flash.net.SharedObjectFlushStatus;
	import flash.net.URLLoader;
	import flash.net.URLLoaderDataFormat;
	import flash.net.URLRequest;
	import flash.net.URLVariables;
	import flash.system.ApplicationDomain;
	import flash.system.LoaderContext;
	import flash.utils.ByteArray;
	import flash.utils.Endian;
	
	public class ResManager implements IResManager
	{
		private static const RES_VERSION_NAME:String = "res";
		private static const SAVEFLAG_NOSET:int = 0;
		private static const SAVEFLAG_CANSAVE:int = 1;
		private static const SAVEFLAG_NOTSAVE:int = 2;
		
		private static var resVsDict:Object = null;
		private static var resObjDict:Object = new Object();
		private static var pattern:RegExp = /[\/.\\]/g;
		private static var saveFlag:int = 0; //0:尚未确定. 1:可以保存. 2:不保存
		private static var variables:URLVariables = null;
		private var _versionTxt:String = "";
		
		public function ResManager()
		{
			loadLocalResVersionConfig();
		}
		
		private function loadLocalResVersionConfig():void
		{
			var so:SharedObject = SharedObject.getLocal(ResManager.RES_VERSION_NAME);
			if (so.data.hasOwnProperty("ResVersion"))
			{
				ResManager.resVsDict = so.data;
				ResManager.saveFlag = ResManager.SAVEFLAG_CANSAVE;
			}
			else
			{
				ResManager.saveFlag = ResManager.SAVEFLAG_NOTSAVE;
			}
		}
		
		public function loadURLResVersion(version:String, onLoadComplete:Function):void
		{
			if (version == null)
			{
				this._versionTxt = "";
				ResManager.resVsDict = new Object();
				ResManager.saveFlag = ResManager.SAVEFLAG_CANSAVE;
				onLoadComplete();
				return;
			}
			this._versionTxt = "?"+version;
			var randomNum:String = Math.floor(Math.random() * 100).toString();
			ResManager.variables = new URLVariables();
			ResManager.variables.v = version;
			ResManager.variables.r = randomNum;
			
			if (ResManager.resVsDict && ResManager.resVsDict["ResVersion"].toString() == version)
			{
				onLoadComplete();
				return;
			}
			var urlRequest:URLRequest = new URLRequest("config/ResVersion.xml");
			urlRequest.data = ResManager.variables;
			var urlLoader:URLLoader = new URLLoader();
			urlLoader.dataFormat = URLLoaderDataFormat.TEXT;
			urlLoader.addEventListener(Event.COMPLETE, loadURLResVersionComplete);
			try
			{
				urlLoader.load(urlRequest);
			}
			catch (err:Error)
			{
				LogPrint.instance().printLog(err,"load version config error");
			}
			
			function loadURLResVersionComplete(evt:Event):void
			{
				ResManager.resVsDict = new Object();
				var so:SharedObject = null;
				if (ResManager.saveFlag == ResManager.SAVEFLAG_CANSAVE)
				{
					so = SharedObject.getLocal(ResManager.RES_VERSION_NAME);
				}
				var vsXml:XML = new XML(urlLoader.data);
				setResVersionDict(vsXml.children(), so);
				flushShareObject(so);
				onLoadComplete();
				urlLoader.removeEventListener(Event.COMPLETE,loadURLResVersionComplete);
			}
		}
		
		private function setResVersionDict(xml:XMLList, sobj:SharedObject = null, name:String=""):void
		{
			for(var i:int = 0; i< xml.length();i++)
			{
				var nd:XML = xml[i];
				var _name:String = name + nd.name().toString();
				if (nd.hasComplexContent())
				{
					setResVersionDict(nd.children(), sobj, _name + "-");
				}
				else
				{
					var _value:String = nd.toString();
					ResManager.resVsDict[_name] = _value;
					if(sobj != null)
						sobj.data[_name] = _value;
				}
			}
		}
		
		
		public function loadImage(path:String, onCompleteFunc:Function, onProgressFunc:Function=null, onIOErrorFunc:Function=null, onSecurityErrorFunc:Function=null):void
		{
			// onCompleteFunc(obj:bitmapData).  onProgressFunc(evt:Event).
			var loadingpath:String = path.replace(pattern, "-");
			if (ResManager.resObjDict[loadingpath])
			{
				onCompleteFunc(ResManager.resObjDict[loadingpath], path);
				return;
			}
			else
			{
				if (ResManager.saveFlag == ResManager.SAVEFLAG_CANSAVE)
				{
					var so:SharedObject = SharedObject.getLocal(loadingpath);
					var obj:Object = so.data["res"];
					if (obj && ResManager.resVsDict[loadingpath]&& so.data["version"].toString() == ResManager.resVsDict[loadingpath].toString())
					{
						var imgLoader:Loader = new Loader();
						imgLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, loadBytesComplete);
						registerEventListener(imgLoader.contentLoaderInfo,onProgressFunc,onIOErrorFunc,onSecurityErrorFunc);
						imgLoader.loadBytes(obj as ByteArray);
						return;
					}
				}
			}
			
			var urlRequest:URLRequest = new URLRequest(path+this._versionTxt);
			urlRequest.data = ResManager.variables;
			var urlLoader:URLLoader = new URLLoader();
			
			urlLoader.dataFormat = URLLoaderDataFormat.BINARY;
			urlLoader.addEventListener(Event.COMPLETE, loadImageComplete);
			registerEventListener(urlLoader,onProgressFunc, onIOErrorFunc, onSecurityErrorFunc);
			try
			{
				urlLoader.load(urlRequest);
			}
			catch (err:Error)
			{
				LogPrint.instance().printLog(err, "load resource error:", path);
			}
			
			function loadImageComplete(evt:Event):void
			{
				var loader:URLLoader = evt.target as URLLoader;
				loader.removeEventListener(Event.COMPLETE, loadImageComplete);
				destroyEventListener(loader,onProgressFunc, onIOErrorFunc, onSecurityErrorFunc);
				
				var bytes:ByteArray = loader.data;
				
				var picLoader:Loader = new Loader();
				picLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, loadBytesComplete);
				picLoader.loadBytes(bytes);
				
				if (ResManager.saveFlag == ResManager.SAVEFLAG_CANSAVE)
				{
					var so:SharedObject = SharedObject.getLocal(loadingpath);
					so.data.res = bytes;
					if (ResManager.resVsDict[loadingpath])
					{
						so.data.version = ResManager.resVsDict[loadingpath].toString();
					}
					else
					{
						so.data.version = "0";
						ResManager.resVsDict[loadingpath] = "0";
					}
					flushShareObject(so);
				}
			}
			
			function loadBytesComplete(evt:Event):void
			{
				LogPrint.instance().printLog("load image complete:", path);
				var picLoader:Loader = evt.currentTarget.loader;
				picLoader.contentLoaderInfo.removeEventListener(Event.COMPLETE, loadBytesComplete);
				destroyEventListener(picLoader.contentLoaderInfo,onProgressFunc, onIOErrorFunc, onSecurityErrorFunc);
				ResManager.resObjDict[loadingpath] = (picLoader.content as Bitmap).bitmapData;
				onCompleteFunc(ResManager.resObjDict[loadingpath], path);
			}
		}
		
		private function registerEventListener(loaderinfo:*,onProgressFunc:Function=null, onIOErrorFunc:Function=null, onSecurityErrorFunc:Function=null):void
		{
			if(onProgressFunc != null)
				loaderinfo.addEventListener(ProgressEvent.PROGRESS,onProgressFunc);
			if(onIOErrorFunc != null)
				loaderinfo.addEventListener(IOErrorEvent.IO_ERROR,onIOErrorFunc);
			if(onSecurityErrorFunc != null)
				loaderinfo.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecurityErrorFunc);
		}
		
		private function destroyEventListener(loaderinfo:*,onProgressFunc:Function=null, onIOErrorFunc:Function=null, onSecurityErrorFunc:Function=null):void
		{
			if(onProgressFunc != null)
				loaderinfo.removeEventListener(ProgressEvent.PROGRESS,onProgressFunc);
			if(onIOErrorFunc != null)
				loaderinfo.removeEventListener(IOErrorEvent.IO_ERROR,onIOErrorFunc);
			if(onSecurityErrorFunc != null)
				loaderinfo.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecurityErrorFunc);
		}
		
		public function loadText(path:String, onCompleteFunc:Function, onProgressFunc:Function=null, onIOErrorFunc:Function=null, onSecurityErrorFunc:Function=null):void
		{
			// 回调函数的定义:
			// onCompleteFunc(obj:String).  onProgressFunc(evt:Event).
			var loadingpath:String = path.replace(pattern, "-");
			if (ResManager.resObjDict[loadingpath])
			{
				onCompleteFunc(ResManager.resObjDict[loadingpath]);
			}
			else
			{
				if (ResManager.saveFlag == ResManager.SAVEFLAG_CANSAVE)
				{
					var so:SharedObject = SharedObject.getLocal(loadingpath);
					var obj:Object = so.data["res"];
					if (ResManager.resVsDict[loadingpath] && obj && so.data["version"].toString() == ResManager.resVsDict[loadingpath].toString())
					{
						ResManager.resObjDict[loadingpath] = so.data.res;
						onCompleteFunc(ResManager.resObjDict[loadingpath]);
						return;
					}
				}
				
				var urlRequest:URLRequest = new URLRequest(path+this._versionTxt);
				urlRequest.data = ResManager.variables;
				var urlLoader:URLLoader = new URLLoader();
				urlLoader.dataFormat = URLLoaderDataFormat.TEXT;
				urlLoader.addEventListener(Event.COMPLETE, loadTextComplete);
				registerEventListener(urlLoader,onProgressFunc, onIOErrorFunc, onSecurityErrorFunc);
				try
				{
					urlLoader.load(urlRequest);
				}
				catch (err:Error)
				{
					LogPrint.instance().printLog(err, "load resource error:", path);
				}
			}
			
			function loadTextComplete(evt:Event):void
			{
				LogPrint.instance().printLog("load text complete:", path);
				var loader:URLLoader = evt.target as URLLoader;
				ResManager.resObjDict[loadingpath] = loader.data;
				destroyEventListener(urlLoader,onProgressFunc, onIOErrorFunc, onSecurityErrorFunc);
				onCompleteFunc(ResManager.resObjDict[loadingpath]);
				
				if (ResManager.saveFlag == ResManager.SAVEFLAG_CANSAVE)
				{
					var so:SharedObject = SharedObject.getLocal(loadingpath);
					so.data.res = loader.data as String;
					if (ResManager.resVsDict[loadingpath])
					{
						so.data.version = ResManager.resVsDict[loadingpath].toString();
					}
					else
					{
						so.data.version = "0";
						ResManager.resVsDict[loadingpath] = "0";
					}
					flushShareObject(so);
				}
			}
		}
		
		
		public function loadSWF(path:String, onCompleteFunc:Function, onProgressFunc:Function=null, onIOErrorFunc:Function=null, onSecurityErrorFunc:Function=null):void
		{
			// 回调函数的定义:
			// onCompleteFunc(evt:Event).  onProgressFunc(evt:Event).
			var loadingpath:String = path.replace(pattern, "-");
			if (ResManager.saveFlag == ResManager.SAVEFLAG_CANSAVE)//这里和下面那个判断暂时屏蔽掉
			{
				var so:SharedObject = SharedObject.getLocal(loadingpath);
				var obj:Object = so.data["res"];
				
				if (obj && ResManager.resVsDict[loadingpath] && so.data["version"].toString() == ResManager.resVsDict[loadingpath].toString())
				{
					var swfLoader:Loader = new Loader();
					swfLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, loadSWFBytesComplete);
					registerEventListener(swfLoader.contentLoaderInfo,onProgressFunc,onIOErrorFunc, onSecurityErrorFunc);
					var context:LoaderContext = new LoaderContext(false);
					context.applicationDomain = new ApplicationDomain(ApplicationDomain.currentDomain);
					swfLoader.loadBytes(obj as ByteArray, context);
					return;
				}
			}
			
			var urlRequest:URLRequest = new URLRequest(path+this._versionTxt);
			urlRequest.data = ResManager.variables;
			var urlLoader:URLLoader = new URLLoader();
			
			urlLoader.dataFormat = URLLoaderDataFormat.BINARY;
			urlLoader.addEventListener(Event.COMPLETE, loadSWFComplete);
			registerEventListener(urlLoader,onProgressFunc,onIOErrorFunc, onSecurityErrorFunc);
			try
			{
				urlLoader.load(urlRequest);
			}
			catch (err:Error)
			{
				LogPrint.instance().printLog(err, "load resource error:", path);
			}
			
			function loadSWFComplete(evt:Event):void
			{
				var loader:URLLoader = evt.target as URLLoader;
				loader.removeEventListener(Event.COMPLETE, loadSWFComplete);
				destroyEventListener(loader,onProgressFunc,onIOErrorFunc, onSecurityErrorFunc);
				var bytes:ByteArray = loader.data;
				var swfLoader:Loader = new Loader();
				
				swfLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, loadSWFBytesComplete);
				var context:LoaderContext = new LoaderContext(false);
				context.applicationDomain = new ApplicationDomain(ApplicationDomain.currentDomain);
				swfLoader.loadBytes(bytes,context);
				var so:SharedObject = SharedObject.getLocal(loadingpath);
				so.data.res = bytes;
				if (ResManager.resVsDict[loadingpath])
				{
					so.data.version = ResManager.resVsDict[loadingpath].toString();
				}
				else
				{
					so.data.version = "0";
					ResManager.resVsDict[loadingpath] = "0";
				}
				flushShareObject(so);
			}
			
			function loadSWFBytesComplete(evt:Event):void
			{
				LogPrint.instance().printLog("load SWF Complete:",path);
				var swfLoader:Loader = evt.currentTarget.loader;
				swfLoader.contentLoaderInfo.removeEventListener(Event.COMPLETE, loadSWFBytesComplete);
				destroyEventListener(swfLoader.contentLoaderInfo,onProgressFunc,onIOErrorFunc, onSecurityErrorFunc);
				onCompleteFunc(evt);
			}
		}
		
		public function checkSharedObjectSaveSetting(onCompleteFunc:Function):void
		{
			var so:SharedObject;
			if (ResManager.saveFlag == ResManager.SAVEFLAG_NOTSAVE)
			{
				so = SharedObject.getLocal("test");
				try
				{
					var flushResult:String = so.flush(1024*1024*100);
					if (flushResult == SharedObjectFlushStatus.PENDING)
					{
						so.addEventListener(NetStatusEvent.NET_STATUS, saveSharedObjectResult);
						return;
					}
					else if (flushResult == SharedObjectFlushStatus.FLUSHED)
					{
						ResManager.saveFlag = ResManager.SAVEFLAG_CANSAVE;
					}
				}
				catch (e:Error)
				{
					LogPrint.instance().printLog("本地存储未开启");
				}
				onCompleteFunc();
			}
			
			function saveSharedObjectResult(evt:NetStatusEvent):void
			{
				if(evt.info.code == "SharedObject.Flush.Success")
				{
					ResManager.saveFlag = ResManager.SAVEFLAG_CANSAVE;
				}
				else
				{
					ResManager.saveFlag = ResManager.SAVEFLAG_NOTSAVE;
				}
				so.removeEventListener(NetStatusEvent.NET_STATUS, saveSharedObjectResult);
				onCompleteFunc();
			}
		}
		
		private function flushShareObject(so:SharedObject):void
		{
			if(ResManager.saveFlag == ResManager.SAVEFLAG_NOTSAVE)
				return;
			try{
				//so.flush();
			}
			catch(e:Error)
			{
				LogPrint.instance().printLog(e.getStackTrace());
			}
		}
		
	}
}